﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Pixysoft.Tools;
using Pixysoft.Framework.Verifications;

namespace Pixysoft.Framework.Sockets.Controller
{
    class SyncSendController
    {
        ReaderWriterLock locker = new ReaderWriterLock();

        List<ActionHandlerCallbackItem> callbacks = new List<ActionHandlerCallbackItem>();


        /// <summary>
        /// 压入调用堆栈
        /// </summary>
        /// <param name="request"></param>
        public void PushCallback(IProtocolMessage request)
        {
            string key = GetSyncSendKey(request);

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                UnsafeRemoveItem(key);

                ActionHandlerCallbackItem item = new ActionHandlerCallbackItem();
                item.Createdate = GlobalTimer.Instance.GetGlobalTime();
                item.Key = key;
                callbacks.Add(item);
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        /// <summary>
        /// 判断调用是否完成
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool IsCompleted(IProtocolMessage request)
        {
            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                string key = GetSyncSendKey(request);

                ActionHandlerCallbackItem item = UnsafeGetItem(key);

                if (key == null)
                    throw Exceptions.UnexpectedResultException("missing sync send callback handler for {0}:{1}",
                        request.Protocol, request.Action);

                return item.IsCompleted;
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        /// <summary>
        /// 弹出调用结果
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        public IProtocolMessage PopCallback(IProtocolMessage request)
        {
            string key = GetSyncSendKey(request);

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                ActionHandlerCallbackItem ritem = UnsafeRemoveItem(key);

                if (ritem == null)
                    return null;

                return ritem.Response;
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }


        /// <summary>
        /// 是否压入了回调
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        public bool HasCallback(IProtocolMessage response)
        {
            string key = GetSyncSendKey(response);

            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                return UnsafeGetItem(key) != null;
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        /// <summary>
        /// 链接回调
        /// </summary>
        /// <param name="session"></param>
        /// <param name="header"></param>
        /// <param name="body"></param>
        public void Callback(IProtocolMessage response)
        {
            string key = GetSyncSendKey(response);

            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                ActionHandlerCallbackItem item = UnsafeGetItem(key);

                item.Response = response;

                item.IsCompleted = true;
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }


        private ActionHandlerCallbackItem UnsafeRemoveItem(string key)
        {
            ActionHandlerCallbackItem ritem = UnsafeGetItem(key);

            if (ritem == null)
                return null;

            callbacks.Remove(ritem);

            return ritem;
        }

        private ActionHandlerCallbackItem UnsafeGetItem(string key)
        {
            ActionHandlerCallbackItem ritem = null;

            foreach (ActionHandlerCallbackItem item in callbacks)
            {
                if (!string.Equals(item.Key, key, StringComparison.OrdinalIgnoreCase))
                    continue;

                ritem = item;
                break;
            }

            return ritem;
        }

        private static string GetSyncSendKey(IProtocolHeader protocol)
        {
            string sendbackkey = string.Format("{0}-{1}-{2}", protocol.Protocol, protocol.Action, protocol.Sn);

            return sendbackkey;
        }
    }

    class ActionHandlerCallbackItem
    {
        string key;
        DateTime createdate;

        bool isCompleted = false;
        IProtocolMessage response;

        public bool IsCompleted
        {
            get { return isCompleted; }
            set { isCompleted = value; }
        }
        public string Key
        {
            get { return key; }
            set { key = value; }
        }
        public DateTime Createdate
        {
            get { return createdate; }
            set { createdate = value; }
        }
        public IProtocolMessage Response
        {
            get { return response; }
            set { response = value; }
        }
    }
}
